package cn.xiaobai.v3;

import cn.xiaobai.utils.LoggerFactory;
import cn.xiaobai.web.TestController;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * tomcat 工厂, 处理web.xml 和 servlet 实例
 *
 * @Author yangdaji
 * @Date 2023/11/29
 * @PackageName cn.xiaobai.v3
 * @ClassName TomcatFactory
 */
public class TomcatFactory {

    static LoggerFactory.Logger log = LoggerFactory.getLogger(TomcatFactory.class);


    private Map<String, MyServlet> servletMapping = new ConcurrentHashMap<>();

    private Map<String, String> servletUriMapping = new ConcurrentHashMap<>();

    private static Map<String, Object> urlBeanMapping = new ConcurrentHashMap<>();


    private static final String WEB_XML = "WEB-INF/web.xml";


    public static TomcatFactory run() {
        TomcatFactory tomcatFactory = new TomcatFactory();
        tomcatFactory.init();
        return tomcatFactory;
    }

    /**
     * 初始化, 读取web.xml 文件, 并解析
     */
    public void init() {
        URL resource = TomcatFactory.class.getClassLoader().getResource(WEB_XML);
        if (resource == null) {
            log.warn("not found web.xml");
            return;
        }
        //  解析 xml 文件
        try {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(resource.openStream());

            // 获取元素
            Map<String, String> servletClassMapping = new HashMap<>();
            NodeList root = document.getElementsByTagName("web-app");
            for (int i = 0; i < root.getLength(); i++) {
                Node item = root.item(i);
                if (item.getNodeType() == Node.ELEMENT_NODE) {
                    // 处理元素
                    Element element = (Element) item;
                    // setup1: servlet
                    NodeList servletNode = element.getElementsByTagName("servlet");
                    for (int i1 = 0; i1 < servletNode.getLength(); i1++) {
                        Node item1 = servletNode.item(i1);
                        if (item.getNodeType() == Node.ELEMENT_NODE) {
                            Element element2 = (Element) item1;
                            String servletName = element2.getElementsByTagName("servlet-name").item(i1).getTextContent();
                            String servletClass = element2.getElementsByTagName("servlet-class").item(i1).getTextContent();
                            servletClassMapping.put(servletName, servletClass);
                        }
                    }

                    // setup2: servlet-mapping
                    NodeList servletMappingNode = element.getElementsByTagName("servlet-mapping");
                    for (int i1 = 0; i1 < servletMappingNode.getLength(); i1++) {
                        Node item1 = servletMappingNode.item(i1);
                        if (item.getNodeType() == Node.ELEMENT_NODE) {
                            Element element2 = (Element) item1;
                            String servletName = element2.getElementsByTagName("servlet-name").item(i1).getTextContent();
                            String url = element2.getElementsByTagName("url-pattern").item(i1).getTextContent();
                            servletUriMapping.put(url, servletName);
                            // todo 后面通过自定义注解检测创建
                            urlBeanMapping.put(url, new TestController());
                        }
                    }

                }
            }

            servletClassMapping.forEach((key, val) -> {
                try {
                    Class<?> aClass = Class.forName(val);
                    Object obj = aClass.newInstance();
                    if (obj instanceof MyServlet) {
                        servletMapping.put(key, (MyServlet) obj);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public MyServlet getServlet(String url) {
        String servletName = servletUriMapping.getOrDefault(url, null);
        if (servletName != null) {
            return servletMapping.getOrDefault(servletName, null);
        }
        return null;
    }

    /**
     * 获取路径的目标执行方法
     *
     * @param url
     * @param cls
     * @param <T>
     * @return
     */
    public static <T> T getControllerBean(String url, Class<T> cls) {
        Object bean = urlBeanMapping.getOrDefault(url, null);
        if (bean != null) {
            if (bean.getClass().equals(cls)) {
                return cls.cast(bean);
            }
        }
        return null;
    }

}
